﻿namespace Sage.CloudStorage.Qiniu.Events
{
    /// <summary>
    /// 分片上传进度事件参数
    /// 提供详细的上传进度信息，支持实时监控上传状态和性能分析
    /// </summary>
    /// <remarks>
    /// **进度监控功能**：
    /// - **实时进度**：提供字节级别和分片级别的进度信息
    /// - **性能指标**：包含传输速度、预计剩余时间等性能数据
    /// - **状态追踪**：详细记录当前上传任务的各项状态信息
    /// - **格式化输出**：提供用户友好的格式化显示方法
    /// 
    /// **应用场景**：
    /// - **进度条显示**：为用户界面提供准确的进度条数据
    /// - **性能监控**：监控上传性能，优化网络配置
    /// - **用户体验**：显示剩余时间，提升用户体验
    /// - **故障诊断**：通过进度数据分析上传问题
    /// - **统计分析**：收集上传统计数据用于分析
    /// </remarks>
    public class UploadProgressEventArgs : EventArgs
    {
        /// <summary>
        /// 已传输字节数
        /// 表示到目前为止已经成功上传的字节总数
        /// </summary>
        public long BytesTransferred { get; set; }

        /// <summary>
        /// 文件总字节数
        /// 表示需要上传的文件的总大小
        /// </summary>
        public long TotalBytes { get; set; }

        /// <summary>
        /// 已完成分片数量
        /// 表示已经成功上传完成的分片数量
        /// </summary>
        public int CompletedParts { get; set; }

        /// <summary>
        /// 总分片数量
        /// 表示文件被分割成的总分片数量
        /// </summary>
        public int TotalParts { get; set; }

        /// <summary>
        /// 上传进度百分比（0-100）
        /// 基于已传输字节数计算得出的百分比进度
        /// </summary>
        /// <remarks>
        /// 计算公式：(BytesTransferred / TotalBytes) * 100
        /// 返回值范围：0.0 - 100.0
        /// 精度：保留小数点后的精确值
        /// </remarks>
        public double ProgressPercentage => TotalBytes > 0 ? (double)BytesTransferred / TotalBytes * 100 : 0;

        /// <summary>
        /// 当前上传任务ID
        /// 七牛云分片上传的唯一标识符
        /// </summary>
        public string UploadId { get; set; } = "";

        /// <summary>
        /// 目标文件键名
        /// 文件在七牛云存储中的完整路径
        /// </summary>
        public string Key { get; set; } = "";

        /// <summary>
        /// 当前正在上传的分片号
        /// 表示触发此进度事件的分片编号（从1开始）
        /// </summary>
        public int CurrentPartNumber { get; set; }

        /// <summary>
        /// 当前分片大小（字节）
        /// 表示当前正在处理的分片的大小
        /// </summary>
        public long CurrentPartSize { get; set; }

        /// <summary>
        /// 上传开始时间
        /// 记录上传任务开始的时间，用于计算传输速度和预计时间
        /// </summary>
        public DateTime StartTime { get; set; } = DateTime.Now;

        /// <summary>
        /// 平均传输速度（字节/秒）
        /// 基于已传输数据量和耗时计算的平均传输速度
        /// </summary>
        /// <remarks>
        /// 计算公式：BytesTransferred / (当前时间 - StartTime).TotalSeconds
        /// 返回值：字节/秒，0表示无法计算（通常是刚开始上传时）
        /// 用途：性能监控、网络状况评估、用户体验优化
        /// </remarks>
        public long AverageSpeed
        {
            get
            {
                var elapsed = (DateTime.Now - StartTime).TotalSeconds;
                return elapsed > 0 ? (long)(BytesTransferred / elapsed) : 0;
            }
        }

        /// <summary>
        /// 预计剩余时间（秒）
        /// 基于当前传输速度预估的剩余上传时间
        /// </summary>
        /// <remarks>
        /// 计算公式：(TotalBytes - BytesTransferred) / AverageSpeed
        /// 返回值：
        /// - 正数：预计剩余秒数
        /// - -1：无法计算（传输速度为0或负数）
        /// 注意：此值是基于当前平均速度的估算，实际时间可能有偏差
        /// </remarks>
        public long EstimatedTimeRemaining
        {
            get
            {
                var speed = AverageSpeed;
                if (speed <= 0) return -1;

                var remainingBytes = TotalBytes - BytesTransferred;
                return remainingBytes / speed;
            }
        }

        /// <summary>
        /// 格式化显示上传速度
        /// 将传输速度转换为用户友好的字符串格式
        /// </summary>
        /// <returns>格式化的速度字符串，如"1.5 MB/s"</returns>
        /// <remarks>
        /// 格式化规则：
        /// - 自动选择合适的单位（B/s、KB/s、MB/s、GB/s等）
        /// - 保留1位小数以提高可读性
        /// - 添加"/s"后缀表示每秒传输量
        /// 
        /// 示例输出：
        /// - "0 B/s" - 没有传输或刚开始
        /// - "150.0 KB/s" - 150千字节每秒
        /// - "2.3 MB/s" - 2.3兆字节每秒
        /// </remarks>
        public string FormatSpeed()
        {
            return FormatBytes(AverageSpeed) + "/s";
        }

        /// <summary>
        /// 格式化显示预计剩余时间
        /// 将剩余时间转换为用户友好的时间字符串
        /// </summary>
        /// <returns>格式化的时间字符串</returns>
        /// <remarks>
        /// 格式化规则：
        /// - 小于60秒：显示为"X秒"
        /// - 小于3600秒：显示为"X分Y秒"
        /// - 大于3600秒：显示为"X小时Y分"
        /// - 无法计算时：显示为"计算中..."
        /// 
        /// 示例输出：
        /// - "计算中..." - 刚开始上传，无法预估
        /// - "45秒" - 预计45秒完成
        /// - "3分25秒" - 预计3分钟25秒完成
        /// - "1小时15分" - 预计1小时15分钟完成
        /// </remarks>
        public string FormatEstimatedTime()
        {
            var seconds = EstimatedTimeRemaining;
            if (seconds < 0) return "计算中...";
            if (seconds < 60) return $"{seconds}秒";
            if (seconds < 3600) return $"{seconds / 60:F0}分{seconds % 60}秒";
            return $"{seconds / 3600:F0}小时{seconds % 3600 / 60:F0}分";
        }

        /// <summary>
        /// 格式化字节数为可读格式
        /// 私有辅助方法，将字节数转换为合适的单位显示
        /// </summary>
        /// <param name="bytes">字节数</param>
        /// <returns>格式化的字节字符串</returns>
        /// <remarks>
        /// 转换规则：
        /// - 使用1024进制（计算机标准）
        /// - 自动选择最合适的单位
        /// - 保留1位小数提高精度
        /// - 支持从B到TB的单位
        /// 
        /// 单位说明：
        /// - B：字节（Byte）
        /// - KB：千字节（Kilobyte，1024 Bytes）
        /// - MB：兆字节（Megabyte，1024 KB）
        /// - GB：吉字节（Gigabyte，1024 MB）
        /// - TB：太字节（Terabyte，1024 GB）
        /// </remarks>
        private static string FormatBytes(long bytes)
        {
            string[] suffixes = ["B", "KB", "MB", "GB", "TB"];
            double size = bytes;
            int suffixIndex = 0;

            while (size >= 1024 && suffixIndex < suffixes.Length - 1)
            {
                size /= 1024;
                suffixIndex++;
            }

            return $"{size:F1} {suffixes[suffixIndex]}";
        }
    }
}
